Conditions | 39 |
Paths | 0 |
Total Lines | 407 |
Lines | 0 |
Ratio | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 1 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like exports.publish often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | "use strict"; |
||
489 | exports.publish = function(taffyData, opts, tutorials) { |
||
490 | data = taffyData; |
||
491 | |||
492 | conf['default'] = conf['default'] || {}; |
||
493 | |||
494 | var templatePath = opts.template; |
||
495 | view = new template.Template(templatePath + '/tmpl'); |
||
496 | |||
497 | // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness |
||
498 | // doesn't try to hand them out later |
||
499 | // var indexUrl = helper.getUniqueFilename( 'index' ); |
||
500 | // don't call registerLink() on this one! 'index' is also a valid longname |
||
501 | |||
502 | // var globalUrl = helper.getUniqueFilename( 'global' ); |
||
503 | helper.registerLink('global', globalUrl); |
||
504 | |||
505 | // set up templating |
||
506 | // set up templating |
||
507 | view.layout = conf['default'].layoutFile ? |
||
508 | path.getResourcePath(path.dirname(conf['default'].layoutFile), |
||
509 | path.basename(conf['default'].layoutFile) ) : 'layout.tmpl'; |
||
510 | |||
511 | // set up tutorials for helper |
||
512 | helper.setTutorials(tutorials); |
||
513 | |||
514 | data = helper.prune(data); |
||
515 | |||
516 | var sortOption = navOptions.sort === undefined ? opts.sort : navOptions.sort; |
||
517 | sortOption = sortOption === undefined ? true : sortOption; |
||
518 | sortOption = sortOption === true ? 'longname, version, since' : sortOption; |
||
519 | if (sortOption) { |
||
520 | data.sort(sortOption); |
||
521 | } |
||
522 | helper.addEventListeners(data); |
||
523 | |||
524 | var sourceFiles = {}; |
||
525 | var sourceFilePaths = []; |
||
526 | data().each(function(doclet) { |
||
527 | doclet.attribs = ''; |
||
528 | |||
529 | if (doclet.examples) { |
||
530 | doclet.examples = doclet.examples.map(function(example) { |
||
531 | var caption, lang; |
||
532 | |||
533 | // allow using a markdown parser on the examples captions (surrounded by useless HTML p tags) |
||
534 | if (example.match(/^\s*(<p>)?<caption>([\s\S]+?)<\/caption>(\s*)([\s\S]+?)(<\/p>)?$/i)) { |
||
535 | caption = RegExp.$2; |
||
536 | example = RegExp.$4 + (RegExp.$1 ? '' : RegExp.$5); |
||
537 | } |
||
538 | |||
539 | var lang = /{@lang (.*?)}/.exec(example); |
||
540 | |||
541 | if (lang && lang[1]) { |
||
542 | example = example.replace(lang[0], ""); |
||
543 | lang = lang[1]; |
||
544 | |||
545 | } else { |
||
546 | lang = null; |
||
547 | } |
||
548 | |||
549 | return { |
||
550 | caption: caption || '', |
||
551 | code: example, |
||
552 | lang: lang || "javascript" |
||
553 | }; |
||
554 | }); |
||
555 | } |
||
556 | if (doclet.see) { |
||
557 | doclet.see.forEach(function(seeItem, i) { |
||
558 | doclet.see[i] = hashToLink(doclet, seeItem); |
||
559 | }); |
||
560 | } |
||
561 | |||
562 | // build a list of source files |
||
563 | var sourcePath; |
||
564 | if (doclet.meta) { |
||
565 | sourcePath = getPathFromDoclet(doclet); |
||
566 | sourceFiles[sourcePath] = { |
||
567 | resolved: sourcePath, |
||
568 | shortened: null |
||
569 | }; |
||
570 | |||
571 | //Check to see if the array of source file paths already contains |
||
572 | // the source path, if not then add it |
||
573 | if (sourceFilePaths.indexOf(sourcePath) === -1) { |
||
574 | sourceFilePaths.push(sourcePath) |
||
575 | } |
||
576 | } |
||
577 | }); |
||
578 | |||
579 | // update outdir if necessary, then create outdir |
||
580 | var packageInfo = (find({ |
||
581 | kind: 'package' |
||
582 | }) || [])[0]; |
||
583 | if (navOptions.disablePackagePath !== true && packageInfo && packageInfo.name) { |
||
584 | if (packageInfo.version) { |
||
585 | outdir = path.join(outdir, packageInfo.name, packageInfo.version); |
||
586 | } else { |
||
587 | outdir = path.join(outdir, packageInfo.name); |
||
588 | } |
||
589 | } |
||
590 | fs.mkPath(outdir); |
||
591 | |||
592 | // copy the template's static files to outdir |
||
593 | var fromDir = path.join( templatePath, 'static' ); |
||
594 | var staticFiles = fs.ls( fromDir, 3 ); |
||
595 | |||
596 | staticFiles.forEach( function ( fileName ) { |
||
597 | var toDir = fs.toDir( fileName.replace( fromDir, outdir ) ); |
||
598 | fs.mkPath( toDir ); |
||
599 | fs.copyFileSync( fileName, toDir ); |
||
600 | } ); |
||
601 | |||
602 | // copy user-specified static files to outdir |
||
603 | var staticFilePaths; |
||
604 | var staticFileFilter; |
||
605 | var staticFileScanner; |
||
606 | if (conf.default.staticFiles) { |
||
607 | // The canonical property name is `include`. We accept `paths` for backwards compatibility |
||
608 | // with a bug in JSDoc 3.2.x. |
||
609 | staticFilePaths = conf.default.staticFiles.include || |
||
610 | conf.default.staticFiles.paths || |
||
611 | []; |
||
612 | staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf.default.staticFiles); |
||
613 | staticFileScanner = new (require('jsdoc/src/scanner')).Scanner(); |
||
614 | |||
615 | staticFilePaths.forEach(function(filePath) { |
||
616 | var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); |
||
617 | |||
618 | extraStaticFiles.forEach(function(fileName) { |
||
619 | var sourcePath = fs.toDir(filePath); |
||
620 | var toDir = fs.toDir( fileName.replace(sourcePath, outdir) ); |
||
621 | fs.mkPath(toDir); |
||
622 | fs.copyFileSync(fileName, toDir); |
||
623 | }); |
||
624 | }); |
||
625 | } |
||
626 | |||
627 | if (sourceFilePaths.length) { |
||
628 | var payload = navOptions.sourceRootPath; |
||
629 | if (!payload) { |
||
630 | payload = path.commonPrefix(sourceFilePaths); |
||
631 | } |
||
632 | sourceFiles = shortenPaths(sourceFiles, payload); |
||
633 | } |
||
634 | data().each(function(doclet) { |
||
635 | var url = helper.createLink(doclet); |
||
636 | helper.registerLink(doclet.longname, url); |
||
637 | |||
638 | // add a shortened version of the full path |
||
639 | var docletPath; |
||
640 | if (doclet.meta) { |
||
641 | docletPath = getPathFromDoclet(doclet); |
||
642 | if (!_.isEmpty(sourceFiles[docletPath])) { |
||
643 | docletPath = sourceFiles[docletPath].shortened; |
||
644 | if (docletPath) { |
||
645 | doclet.meta.shortpath = docletPath; |
||
646 | } |
||
647 | } |
||
648 | } |
||
649 | }); |
||
650 | |||
651 | data().each(function(doclet) { |
||
652 | var url = helper.longnameToUrl[doclet.longname]; |
||
653 | |||
654 | if (url.indexOf('#') > -1) { |
||
655 | doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); |
||
656 | } else { |
||
657 | doclet.id = doclet.name; |
||
658 | } |
||
659 | |||
660 | if (needsSignature(doclet)) { |
||
661 | addSignatureParams(doclet); |
||
662 | addSignatureReturns(doclet); |
||
663 | addAttribs(doclet); |
||
664 | } |
||
665 | }); |
||
666 | |||
667 | // do this after the urls have all been generated |
||
668 | data().each(function(doclet) { |
||
669 | doclet.ancestors = getAncestorLinks(doclet); |
||
670 | |||
671 | if (doclet.kind === 'member') { |
||
672 | addSignatureTypes(doclet); |
||
673 | addAttribs(doclet); |
||
674 | } |
||
675 | |||
676 | if (doclet.kind === 'constant') { |
||
677 | addSignatureTypes(doclet); |
||
678 | addAttribs(doclet); |
||
679 | doclet.kind = 'member'; |
||
680 | } |
||
681 | }); |
||
682 | |||
683 | var members = helper.getMembers(data); |
||
684 | members.tutorials = tutorials.children; |
||
685 | |||
686 | // add template helpers |
||
687 | view.find = find; |
||
688 | view.linkto = linkto; |
||
689 | view.resolveAuthorLinks = resolveAuthorLinks; |
||
690 | view.tutoriallink = tutoriallink; |
||
691 | view.htmlsafe = htmlsafe; |
||
692 | view.moment = moment; |
||
693 | |||
694 | // once for all |
||
695 | buildNav(members); |
||
696 | view.nav = navigationMaster; |
||
697 | view.navOptions = navOptions; |
||
698 | attachModuleSymbols(find({ |
||
699 | kind: ['class', 'function'], |
||
700 | longname: { |
||
701 | left: 'module:' |
||
702 | } |
||
703 | }), |
||
704 | members.modules); |
||
705 | |||
706 | // only output pretty-printed source files if requested; do this before generating any other |
||
707 | // pages, so the other pages can link to the source files |
||
708 | if (navOptions.outputSourceFiles) { |
||
709 | generateSourceFiles(sourceFiles); |
||
710 | } |
||
711 | |||
712 | if (members.globals.length) { |
||
713 | generate('global', 'Global', [{ |
||
714 | kind: 'globalobj' |
||
715 | }], globalUrl); |
||
716 | } |
||
717 | |||
718 | // some browsers can't make the dropdown work |
||
719 | if (view.nav.module && view.nav.module.members.length) { |
||
720 | generate('module', view.nav.module.title, [{ |
||
721 | kind: 'sectionIndex', |
||
722 | contents: view.nav.module |
||
723 | }], navigationMaster.module.link); |
||
724 | } |
||
725 | |||
726 | if (view.nav.class && view.nav.class.members.length) { |
||
727 | generate('class', view.nav.class.title, [{ |
||
728 | kind: 'sectionIndex', |
||
729 | contents: view.nav.class |
||
730 | }], navigationMaster.class.link); |
||
731 | } |
||
732 | |||
733 | if (view.nav.namespace && view.nav.namespace.members.length) { |
||
734 | generate('namespace', view.nav.namespace.title, [{ |
||
735 | kind: 'sectionIndex', |
||
736 | contents: view.nav.namespace |
||
737 | }], navigationMaster.namespace.link); |
||
738 | } |
||
739 | |||
740 | if (view.nav.mixin && view.nav.mixin.members.length) { |
||
741 | generate('mixin', view.nav.mixin.title, [{ |
||
742 | kind: 'sectionIndex', |
||
743 | contents: view.nav.mixin |
||
744 | }], navigationMaster.mixin.link); |
||
745 | } |
||
746 | |||
747 | if (view.nav.interface && view.nav.interface.members.length) { |
||
748 | generate('interface', view.nav.interface.title, [{ |
||
749 | kind: 'sectionIndex', |
||
750 | contents: view.nav.interface |
||
751 | }], navigationMaster.interface.link); |
||
752 | } |
||
753 | |||
754 | if (view.nav.external && view.nav.external.members.length) { |
||
755 | generate('external', view.nav.external.title, [{ |
||
756 | kind: 'sectionIndex', |
||
757 | contents: view.nav.external |
||
758 | }], navigationMaster.external.link); |
||
759 | } |
||
760 | |||
761 | if (view.nav.tutorial && view.nav.tutorial.members.length) { |
||
762 | generate('tutorial', view.nav.tutorial.title, [{ |
||
763 | kind: 'sectionIndex', |
||
764 | contents: view.nav.tutorial |
||
765 | }], navigationMaster.tutorial.link); |
||
766 | } |
||
767 | |||
768 | // index page displays information from package.json and lists files |
||
769 | var files = find({ |
||
770 | kind: 'file' |
||
771 | }), |
||
772 | packages = find({ |
||
773 | kind: 'package' |
||
774 | }); |
||
775 | |||
776 | generate('index', 'Index', |
||
777 | packages.concat( |
||
778 | [{ |
||
779 | kind: 'mainpage', |
||
780 | readme: opts.readme, |
||
781 | longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page' |
||
782 | }] |
||
783 | ).concat(files), |
||
784 | indexUrl); |
||
785 | |||
786 | // set up the lists that we'll use to generate pages |
||
787 | var classes = taffy(members.classes); |
||
788 | var modules = taffy(members.modules); |
||
789 | var namespaces = taffy(members.namespaces); |
||
790 | var mixins = taffy(members.mixins); |
||
791 | var interfaces = taffy(members.interfaces); |
||
792 | var externals = taffy(members.externals); |
||
793 | |||
794 | for (var longname in helper.longnameToUrl) { |
||
795 | if (hasOwnProp.call(helper.longnameToUrl, longname)) { |
||
796 | var myClasses = helper.find(classes, { |
||
797 | longname: longname |
||
798 | }); |
||
799 | if (myClasses.length) { |
||
800 | generate('class', 'Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); |
||
801 | } |
||
802 | |||
803 | var myModules = helper.find(modules, { |
||
804 | longname: longname |
||
805 | }); |
||
806 | if (myModules.length) { |
||
807 | generate('module', 'Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); |
||
808 | } |
||
809 | |||
810 | var myNamespaces = helper.find(namespaces, { |
||
811 | longname: longname |
||
812 | }); |
||
813 | if (myNamespaces.length) { |
||
814 | generate('namespace', 'Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); |
||
815 | } |
||
816 | |||
817 | var myMixins = helper.find(mixins, { |
||
818 | longname: longname |
||
819 | }); |
||
820 | if (myMixins.length) { |
||
821 | generate('mixin', 'Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); |
||
822 | } |
||
823 | |||
824 | var myInterfaces = helper.find(interfaces, { |
||
825 | longname: longname |
||
826 | }); |
||
827 | if (myInterfaces.length) { |
||
828 | generate('interface', 'Interface: ' + myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname]); |
||
829 | } |
||
830 | |||
831 | var myExternals = helper.find(externals, { |
||
832 | longname: longname |
||
833 | }); |
||
834 | if (myExternals.length) { |
||
835 | generate('external', 'External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); |
||
836 | } |
||
837 | } |
||
838 | } |
||
839 | |||
840 | // TODO: move the tutorial functions to templateHelper.js |
||
841 | function generateTutorial(title, tutorial, filename) { |
||
842 | var tutorialData = { |
||
843 | title: title, |
||
844 | header: tutorial.title, |
||
845 | content: tutorial.parse(), |
||
846 | children: tutorial.children, |
||
847 | docs: null |
||
848 | }; |
||
849 | |||
850 | var tutorialPath = path.join(outdir, filename), |
||
851 | html = view.render('tutorial.tmpl', tutorialData); |
||
852 | |||
853 | // yes, you can use {@link} in tutorials too! |
||
854 | html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> |
||
855 | |||
856 | if (searchEnabled) { |
||
857 | searchableDocuments[filename] = { |
||
858 | "id": filename, |
||
859 | "title": title, |
||
860 | "body": searchData(html) |
||
861 | }; |
||
862 | } |
||
863 | |||
864 | fs.writeFileSync(tutorialPath, html, 'utf8'); |
||
865 | } |
||
866 | |||
867 | // tutorials can have only one parent so there is no risk for loops |
||
868 | function saveChildren(node) { |
||
869 | node.children.forEach(function(child) { |
||
870 | generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); |
||
871 | saveChildren(child); |
||
872 | }); |
||
873 | } |
||
874 | |||
875 | function generateQuickTextSearch(templatePath, searchableDocuments, navOptions) { |
||
876 | var data = { |
||
877 | searchableDocuments: JSON.stringify(searchableDocuments), |
||
878 | navOptions: navOptions |
||
879 | }; |
||
880 | |||
881 | var tmplString = fs.readFileSync(templatePath + "/quicksearch.tmpl").toString(), |
||
882 | tmpl = _.template(tmplString); |
||
883 | |||
884 | var html = tmpl(data), |
||
885 | outpath = path.join(outdir, "quicksearch.html"); |
||
886 | |||
887 | fs.writeFileSync(outpath, html, "utf8"); |
||
888 | } |
||
889 | |||
890 | saveChildren(tutorials); |
||
891 | |||
892 | if (searchEnabled) { |
||
893 | generateQuickTextSearch(templatePath + '/tmpl', searchableDocuments, navOptions); |
||
894 | } |
||
895 | }; |
||
896 |